package lab.chapter;

import lombok.Getter;
import lombok.Setter;

import java.util.*;

/**
 * 代表自动机状态
 */
@Getter
@Setter
public class State {
    // 计数器，状态名字
    private static int count = 0;

    // 状态名称， 0，1，。。。。
    private String name;

    // 是否是最终态
    private boolean acceptable = false;

    // 状态间连线
    private List<Transition> transitions = new LinkedList<>();

    // 连线与下一状态的对照表
    private Map<Transition, State> transition2State = new HashMap<>();

    // 节点关联的语法。词法分析时，分辨是哪个词法的结束状态
    private GrammarNode grammarNode = null;

    public State() {
        name = String.valueOf(count++);
    }

    public State(boolean acceptable) {
        this();
        this.acceptable = acceptable;
    }

    /**
     * 添加迁移状态
     * @param transition 迁移条件
     * @param toState 迁移状态
     */
    public void addTransition(Transition transition, State toState) {
        transitions.add(transition);
        transition2State.put(transition, toState);
    }

    /**
     * 复制另一个状态。相当于把State这个节点替换成自己
     * @param state 源状态
     */
    public void copyTransitions(State state) {
        this.transitions = state.transitions;
        this.transition2State = state.transition2State;
    }

    public State getState(Transition transition) {
        return transition2State.get(transition);
    }

    /**
     * 获取某个状态的 Transition。
     * 这里假设每个两个状态之间只可能有一个Transition
     * @param toState 迁移的状态
     * @return transition
     */
    public Transition getTransitionTo(State toState) {
        for (Transition transition: transitions) {
            if (transition2State.get(transition) == toState) {
                return transition;
            }
        }
        return null;
    }

    public List<Transition> transitions() {
        return Collections.unmodifiableList(transitions);
    }

    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append(name);
        if (transitions.size() > 0) {
            for (Transition transition : transitions) {
                State state = transition2State.get(transition);
                sb.append("\t").append(transition).append(" -> ").append(state.name).append("\n");
            }
        } else {
            sb.append("\t(end)").append("\n");
        }
        if (isAcceptable()) {
            sb.append("\tacceptable\n");
        }
        return sb.toString();
    }

    public boolean isAcceptable() {
        return acceptable;
    }

    protected void dump() {
        dump(this, new HashSet<>());
    }

    /**
     * 打印 FSA 中的所有状态
     * @param state 状态
     * @param dumpedStates 已经打印的状态
     */
    private static void dump(State state, Set<State> dumpedStates) {
        System.out.println(state);
        dumpedStates.add(state);
        for (Transition transition : state.transitions()) {
            State state1 = state.getState(transition);
            if (!dumpedStates.contains(state1)) {
                dump(state1, dumpedStates);
            }
        }
    }
}
